﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Pavilion.DesignerTool.ViewTools.ConnectableListBox;
using System.ComponentModel;

namespace Pavilion.DesignerTool
{
    public class NodeBaseWrapper : IConnectableItem, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public NodeBase Node { get; set; }
        public ContainerNodeWrapper ParentContainerNodeWrapper { get; set; }
        public NotifiableCollection<GameDataWrapper> GameDataWrapperCollection { get; private set; }
        public object Data { get { return Node; } }
        public Point Position { get; set; }
        public string Name { get { return Node.Name; } set { SetName(value); } }
        public string TypeName { get { return Node.GetType().Name; } }
        public NodeScriptWrapper NodeScriptWrapper { get { return nodeScriptWrapper; } set { SetNodeScriptWrapper(value); } }
        public bool IsNodeCurrentlyPlaying { get { return isNodeCurrentlyPlaying; } set { SetIsNodeCurrentlyPlaying(value); } }

        private NodeScriptWrapper nodeScriptWrapper;
        private bool isNodeCurrentlyPlaying;
        static private List<NodeBaseWrapper> currentlyPlayingNodes = new List<NodeBaseWrapper>();

        public NodeBaseWrapper(NodeBase node, NodeScriptWrapper nodeScriptWrapper)
        {
            this.Node = node;
            this.NodeScriptWrapper = nodeScriptWrapper;
            GameDataWrapperCollection = new NotifiableCollection<GameDataWrapper>();
            this.Position = new Point(0, 0);

            foreach (GameData gameData in node.GameDataCollection)
            {
                GameDataWrapper gameDataWrapper = new GameDataWrapper(gameData, this);
                GameDataWrapperCollection.Add(gameDataWrapper);
            }
        }

        public virtual void Dispose() { }

        static public NodeBaseWrapper CreateNodeBaseWrapper(NodeBase node)
        {
            if (node is ContainerNode)
                return new ContainerNodeWrapper(node as ContainerNode, null);
            else if (node is AnimationNode)
                return new AnimationNodeWrapper(node as AnimationNode, null);
            else if (node is LoadNode)
                return new LoadNodeWrapper(node as LoadNode, null);
            else
                return new NodeBaseWrapper(node, null);
        }

        internal GameDataWrapper AddGameData(GameData gameData)
        {
            GameDataWrapper gameDataWrapper = new GameDataWrapper(gameData, this);

            Node.GameDataCollection.Add(gameData);
            GameDataWrapperCollection.Add(gameDataWrapper);
            GameDataTransfer.AddGameData(gameDataWrapper);

            return gameDataWrapper;
        }

        internal void RemoveGameData(GameDataWrapper gameDataWrapper)
        {
            int index = GameDataWrapperCollection.IndexOf(gameDataWrapper);

            Node.GameDataCollection.RemoveAt(index);
            GameDataWrapperCollection.RemoveAt(index);

            GameDataTransfer.RemoveGameData(NodeScriptWrapper.ResourceData.ResourceName, NodeScriptWrapper.Name, Node, index);
        }

        private void SetName(string value)
        {
            if (Node.Name == value)
                return;

            if (ParentContainerNodeWrapper.ContainerNode.Contains(value))
            {
                MessageBox.Show("Can not change node name to '" + value + "'. It already exists.");
                return;
            }

            string oldName = Node.Name;
            Node.Name = value;
            NodeTransfer.Rename(NodeScriptWrapper.ResourceData.ResourceName, NodeScriptWrapper.Name, Node, oldName, Node.Name);
            OnPropertyChanged("Name");
        }

        private void SetIsNodeCurrentlyPlaying(bool value)
        {
            if (isNodeCurrentlyPlaying == value)
                return;

            isNodeCurrentlyPlaying = value;
            OnPropertyChanged("IsNodeCurrentlyPlaying");

            if (value)
                currentlyPlayingNodes.Add(this);
            else
                currentlyPlayingNodes.Remove(this);
        }

        protected virtual void SetNodeScriptWrapper(NodeScriptWrapper value)
        {
            nodeScriptWrapper = value;
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        static public void DisableAllCurrentlyPlayingNodes()
        {
            for (int i = 0; i < currentlyPlayingNodes.Count;)
                currentlyPlayingNodes[i].IsNodeCurrentlyPlaying = false;
        }
    }
}
